signature SEMANT =
sig
    val transProg : Absyn.exp -> Translate.frag list
end

structure Semant : SEMANT =
struct
    structure A = Absyn
    structure E = ErrorMsg
    structure M = Temp
    structure S = Symbol
    structure T = Types
    structure V = Env
    structure X = Translate

    fun typeError pos msg = E.error pos ("type error: " ^ msg)

    fun commaSep [] = ""
      | commaSep [s] = s
      | commaSep (s::ss) = s ^ ", " ^ (commaSep ss)
			   
    type expty = { exp : X.exp, ty : T.ty }

    fun unparseTy T.INT = "int"
      | unparseTy T.STRING = "string"
      | unparseTy T.UNIT = "unit"
      | unparseTy T.NIL = "nil"
      | unparseTy (T.NAME (name, ref NONE)) = "unknown type " ^ (S.name name)
      | unparseTy (T.NAME (name, ref (SOME _))) = S.name name
      | unparseTy (T.ARRAY (ty, _)) = "[" ^ (unparseTy ty) ^ "]"
      | unparseTy (T.RECORD (sts, _)) = "{" ^ (commaSep (map (fn (name, ty) => (S.name name) ^ ":" ^ (unparseTy ty)) sts)) ^ "}"

    (* checkInt : expty * pos -> unit *)
    fun checkInt (expty, pos) = ...

    (* transTy : tenv * Absyn.ty -> Types.ty *)
    fun transTy ...
					       
    (* transDec : (tenv * venv * dec) -> (venv, tenv) *)
    and transDec (venv, tenv, A.VarDec{name, typ=NONE, init, ...}) =
	let val  = {exp, ty} = transExp(venv, tenv, init)
	in {tenv=tenv,
	    venv=S.enter(venv, name, E.VarEntry{ty=ty})
	end
      | transDec (venv, tenv, A.TypeDec[{name, ty, pos}]) =
	{venv=venv,
	 tenv=S.enter(tenv, name, transTy(tenv, ty))}
      | transDec (venv, tenv, A.FunctionDev[{name, params, body, pos, result=SOME(rt, pos)}]) =
	let val SOME(result_ty) = S.look(tenv, rt)
	    fun transParam {name, typ, pos} = case S.look(tenv, typ)
					      of SOME t => {name=name, ty=t}
	    val params' = map transParam params
	    val venv' = S.enter(venv, name, E.FunEntry {formals=map #ty params', result=result_ty})
	    fun enterParam ({name, ty}, venv) = S.enter (venv, name, E.VarEntry{access={}, ty})
	    val venv'' = fold enterParam params' venv'
	in ( transExp(venv'', tenv) body
	   ; {venv=venv', tenv=tenv}
	   )
	end
							    
    (* transExp : (venv, tenv -> exp -> expty *)
    and transExp (venv, tenv) =
        let fun trExp (A.OpExp{left,oper=A.PlusOp,right,pos}) =
		( checkInt (tyl, pos, "left operand to +")
		; checkInt (tyr, pos, "right operand to +")
		; {exp = (), ty = T.INT}
		)
	      | trExp (A.RecordExp ...) ...
	      | trExp (A.LetExp{decs, body, pos}) =
		let val  = {venv = venv', tenv=tenv'} = transDecs (venv, tenv, decs)
		in transExp(venv', tenv') body
		end

	    and trVar (A.SimpleVar(id,pos)) =
		( case S.look (venv, id)
		   of SOME (V.VarEntry{ty}) => {exp = (), ty = actualTy ty}
		    | NONE => ( error pos ("undefined variable: " ^ (S.name id))
			      ; { exp=(), ty=T.INT }
			      )
		)
	      | trVar (A.FieldVar(v, id, pos)) = ...
	in trExp
	end

    (* transProg A.exp -> unit *)
    fun transProg exp = ...

end
